package blue.web.commons.service;

import blue.commons.enums.OperatorEnum;
import blue.commons.models.TitleValue;
import blue.tools.commons.Md5Utils;
import blue.tools.constants.BlueContants;
import blue.web.cache.service.RedisService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class TreeService {

    private final String prefix_cache_treeServiceNodeKey="treeServiceNodeKey";

    @Autowired
    private RedisService redisService;
    public String getResultTree(String key,TitleValue newNode,String treeData,Integer type){
        String data= StringUtils.EMPTY;
        //设定-1为默认根节点，并且 只有增加节点的时候才生效
        if("-1".equalsIgnoreCase(key) && OperatorEnum.ADD.getKey() !=type){
            return treeData;
        }

        if("-1".equalsIgnoreCase(key) || StringUtils.isBlank(treeData) ){//只有新建的时候才会用-1
            newNode.setValue(StringUtils.isBlank(newNode.getValue())?UUID.randomUUID().toString():newNode.getValue());
            List result=new LinkedList();
            result.add(newNode);
            data= JSONArray.toJSONString(result);
        }else{
            if(StringUtils.isNotBlank(treeData)){
                List<TitleValue> titleValueList=JSONArray.parseArray(treeData,TitleValue.class);
                List removedList=new LinkedList();
                for(TitleValue titleValue:titleValueList){
                    iterationChild(titleValue,key,newNode,type);
                    if(StringUtils.isBlank(titleValue.getValue())){
                        removedList.add(titleValue);
                    }
                }
                titleValueList.removeAll(removedList);
                data=JSONArray.toJSONString(titleValueList);
            }
        }

        return data;
    }


    private void iterationChild(TitleValue titleValue, String key, TitleValue newNode, Integer type){
        if(titleValue==null || StringUtils.isBlank(key)) return;

        if(key.equalsIgnoreCase(titleValue.getValue())){
            if(OperatorEnum.ADD.getKey()==type){//在key下添加子节点
                newNode.setValue(StringUtils.isBlank(newNode.getValue())?UUID.randomUUID().toString():newNode.getValue());
                List childrent=titleValue.getChildren();
                if(CollectionUtils.isEmpty(childrent)){
                    childrent=new LinkedList();
                }
                childrent.add(newNode);
                titleValue.setChildren(childrent);
            } else if(OperatorEnum.MODIFY.getKey()==type){//修改
                titleValue.setTitle(newNode.getTitle());
                titleValue.setExtend(newNode.getExtend());
            }else if(OperatorEnum.DELETE.getKey()==type){//删除
                titleValue.setValue(null);
            }
        }else {
            if(CollectionUtils.isNotEmpty(titleValue.getChildren())){
                List removedList=new LinkedList();
                for(TitleValue subItem:titleValue.getChildren()){
                    iterationChild(subItem,key,newNode,type);
                    if(StringUtils.isBlank(subItem.getValue())){
                        removedList.add(subItem);
                    }
                }
                titleValue.getChildren().removeAll(removedList);
            }
        }
    }


    public TitleValue getNodeByKey(String key,TitleValue titleValue){
        if(titleValue==null || StringUtils.isBlank(key)) return null;
        if(key.equalsIgnoreCase(titleValue.getValue())){
            return titleValue;
        }else {
            if(CollectionUtils.isNotEmpty(titleValue.getChildren())){
                List removedList=new LinkedList();
                for(TitleValue subItem:titleValue.getChildren()){
                    TitleValue node=getNodeByKey(key,subItem);
                    if(node!=null){
                        subItem.setTitle(node.getTitle());
                        subItem.setValue(node.getValue());
                        subItem.setExtend(node.getExtend());
                        return subItem;
                    }
                    if(StringUtils.isBlank(subItem.getValue())){
                        removedList.add(subItem);
                    }
                }
                titleValue.getChildren().removeAll(removedList);
            }
        }

        return null;
    }

    public TitleValue getNodeByKey(String key,String treeData){
        if(StringUtils.isBlank(key) || StringUtils.isBlank(treeData)) return null;

        List<TitleValue> titleValueList=JSONArray.parseArray(treeData,TitleValue.class);
        for(TitleValue titleValue:titleValueList){
            TitleValue node=getNodeByKey(key,titleValue);

            if(node!=null){
                return node;
            }
        }

        return null;
    }

    public TitleValue getNodeByKey(String key,String treeData,boolean isFromCache){
        if(StringUtils.isBlank(key) || StringUtils.isBlank(treeData)) return null;

        String md5Key=Md5Utils.getMD5(String.format("%s_%s",key,treeData));

        if(isFromCache){
            Object cacheObject=redisService.getValue(String.format("%s_%s",prefix_cache_treeServiceNodeKey,md5Key));
            if(cacheObject!=null){
                return JSONObject.parseObject(cacheObject.toString(),TitleValue.class);
            }
        }

        TitleValue titleValue=getNodeByKey(key,treeData);
        if(titleValue!=null){
            redisService.setValue(String.format("%s_%s",prefix_cache_treeServiceNodeKey,md5Key),JSONObject.toJSONString(titleValue),BlueContants.twoDay);
        }

        return titleValue;

    }

    public List<TitleValue> getNodeListByKeys(String keys,String data){
        List<TitleValue> result=new LinkedList();
        if(StringUtils.isBlank(keys) || StringUtils.isBlank(data)){
            return result;
        }

        for(String key:StringUtils.split(keys,",")){
            TitleValue titleValue=getNodeByKey(key,data);
            if(titleValue!=null){
                result.add(titleValue);
            }
        }

        return result;
    }



    public List<TitleValue> getLeafNodes(TitleValue titleValue,String index){
        List<TitleValue> result=new LinkedList<>();
        if(titleValue==null) return result;

        if(CollectionUtils.isEmpty(titleValue.getChildren())){
            titleValue.setIndex(index);
            result.add(titleValue);
            return result;
        }
        int subIndex=1;
        for(TitleValue item:titleValue.getChildren()){
            result.addAll(getLeafNodes(item,String.format("%s-%s",index,subIndex++)));
        }

        return result;
    }


    public List<TitleValue> getLeafNodes(String treeData){
        List<TitleValue> result=new LinkedList<>();
        if(StringUtils.isBlank(treeData)) return result;

        Object cacheObject=redisService.getValue(Md5Utils.getMD5(treeData));
        if(cacheObject!=null){
            return JSONArray.parseArray(cacheObject.toString(),TitleValue.class);
        }

        List<TitleValue> titleValueList=JSONArray.parseArray(treeData,TitleValue.class);
        int index=1;
        for(TitleValue item:titleValueList){
            result.addAll(getLeafNodes(item,String.format("%s",index++)));
        }

        Collections.sort(result, new Comparator<TitleValue>() {
            @Override
            public int compare(TitleValue o1, TitleValue o2) {
                return o1.getIndex().compareTo(o2.getIndex());
            }
        });

        redisService.setValue(Md5Utils.getMD5(treeData),JSONArray.toJSONString(result), BlueContants.day);
        return result;
    }

    public HashMap getLeafNodesMap(String treeData){
       List<TitleValue> nodeList=getLeafNodes(treeData);
       if(CollectionUtils.isEmpty(nodeList)){
           return null;
       }

       HashMap<String,TitleValue> result=new HashMap();
       for(TitleValue titleValue:nodeList){
           result.put(titleValue.getValue(),titleValue);
       }
       return result;
    }


}
